home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue55 / Persist / BDEReg2.pas next >
Encoding:
Pascal/Delphi Source File  |  2000-02-02  |  18.3 KB  |  634 lines

  1. unit BDEReg2;
  2. {
  3. Author     : Guy Smith-Ferrier
  4. Date       : February 2000
  5. Description:
  6. This unit is a block copy of the TBDEDesigner, TDBDataSetEditor, TTableEditor,
  7. TQueryEditor and TStoredProcEditor classes in Delphi 5's own BDEReg.PAS. There
  8. have been no changes to this code whatsoever. The reason for creating this new
  9. unit is simply to change the scope of the classes so that they are in the
  10. interface section instead of in the implementation section. This allows the
  11. classes to be inherited from.
  12. }
  13.  
  14. interface
  15.  
  16. uses
  17.   BDEReg, DSDesign,
  18.   Report, RSConsts, LibHelp, Dialogs, DBLookup, FileCtrl,
  19.   SysUtils, Classes, Menus, DBTables, DB, DRIntf, LibIntf, DsnDBCst,
  20.   DSAttrS, DSAttrA, DBReg, DbXPlor, BDEConst, GQEDelph, ColnEdit, TblDsgn,
  21.   DsgnIntf, DBEdit, IxEdit, UpdSqlEd, FldLinks, CnColEdt, DRTable,
  22.   CustomModuleEditors,
  23.   ParentageSupport, DsnDB,
  24.   ModelViews, ModelPrimitives, DataModelViews, DataModelSupport;
  25.  
  26. type
  27.   TMenuItemID = (miSeparator, miRetrieve, miSave, miSaveAs, miAssociate, miUnassociate);
  28.  
  29.   TBDEDesigner = class(TDSDesigner)
  30.   private
  31.     FTableID: TTableID;
  32.     FQueryDescs: TQueryDescription;
  33.     FMenuArray: array [TMenuItemID] of TMenuItem;
  34.   protected
  35.     procedure AttributeClick(Sender: TObject);
  36.     function QualifyTableName(DatabaseName: string;
  37.       Database: TDatabase; const TableName: string): string;
  38.     function CheckAttribute(Field: TField): Boolean;
  39.     procedure GetTableDesc(var ADatabase, ATable: string);
  40.     procedure GetFieldInfo(Field: TField; var FieldID: TFieldID;
  41.       var AttrID: TAttrID);
  42.     function FindFieldInfo(Field: TField; var FieldID: TFieldID;
  43.       var AttrID: TAttrID): Boolean;
  44.     function RetrieveAttributes(Field: TField): Boolean;
  45.     function SaveAttributes(Field: TField): Boolean;
  46.     function SaveAttributesAs(Field: TField): Boolean;
  47.     function AssociateAttributes(Field: TField): Boolean;
  48.     function UnassociateAttributes(Field: TField): Boolean;
  49.   public
  50.     destructor Destroy; override;
  51.     procedure BeginCreateFields; override;
  52.     function DoCreateField(const FieldName: string; Origin: string): TField; override;
  53.     procedure EndCreateFields; override;
  54.     function GetControlClass(Field: TField): string; override;
  55.     procedure InitializeMenu(Menu: TPopupMenu); override;
  56.     procedure UpdateMenus(Menu: TPopupMenu; EditState: TEditState); override;
  57.   end;
  58.  
  59.   TDBDataSetEditor = class(TDataSetEditor)
  60.   protected
  61.     function GetDSDesignerClass: TDSDesignerClass; override;
  62.   public
  63.     procedure ExecuteVerb(Index: Integer); override;
  64.     function GetVerb(Index: Integer): string; override;
  65.     function GetVerbCount: Integer; override;
  66.   end;
  67.  
  68.   TTableEditor = class(TDBDataSetEditor)
  69.   private
  70.     FActions: TTableDesignActions;
  71.     procedure UpdateActions;
  72.     function IndexToAction(Index: Integer): TTableDesignAction;
  73.   public
  74.     procedure ExecuteVerb(Index: Integer); override;
  75.     function GetVerb(Index: Integer): string; override;
  76.     function GetVerbCount: Integer; override;
  77.   end;
  78.  
  79.   TQueryEditor = class(TDBDataSetEditor)
  80.   public
  81.     procedure ExecuteVerb(Index: Integer); override;
  82.     function GetVerb(Index: Integer): string; override;
  83.     function GetVerbCount: Integer; override;
  84.   end;
  85.  
  86.   TStoredProcEditor = class(TDBDataSetEditor)
  87.   public
  88.     procedure ExecuteVerb(Index: Integer); override;
  89.     function GetVerb(Index: Integer): string; override;
  90.     function GetVerbCount: Integer; override;
  91.   end;
  92.  
  93. implementation
  94.  
  95. destructor TBDEDesigner.Destroy;
  96. begin
  97.   inherited Destroy;
  98.   if DSDesign.DesignerCount <= 0 then DictionaryDeactivate;
  99. end;
  100.  
  101. function TBDEDesigner.QualifyTableName(DatabaseName: string;
  102.   Database: TDatabase; const TableName: string): string;
  103. begin
  104.   if not Assigned(Database) then
  105.     Result := QualifyTableNameByName(TDBDataset(Dataset).SessionName,
  106.       DatabaseName, TableName) else
  107.     Result := DrIntf.QualifyTableName(Database, TableName);
  108. end;
  109.  
  110. procedure TBDEDesigner.GetTableDesc(var ADatabase, ATable: string);
  111. var
  112.   Database: TDatabase;
  113. begin
  114.   ADatabase := '';
  115.   ATable := '';
  116.   if Dataset is TTable then
  117.   begin
  118.     ADatabase := TTable(Dataset).DatabaseName;
  119.     Database := TTable(Dataset).Database;
  120.     ATable := QualifyTableName(ADatabase, Database, TTable(Dataset).TableName);
  121.   end;
  122. end;
  123.  
  124. function TBDEDesigner.CheckAttribute(Field: TField): Boolean;
  125. var
  126.   FieldID: TFieldID;
  127.   AttrID: TAttrID;
  128. begin
  129.   Result := False;
  130.   if Field.AttributeSet <> '' then Exit;
  131.   FindFieldInfo(Field, FieldID, AttrID);
  132.   if not IsNullID(AttrID) then Exit;
  133.   Result := True;
  134. end;
  135.  
  136. procedure TBDEDesigner.GetFieldInfo(Field: TField; var FieldID: TFieldID;
  137.   var AttrID: TAttrID);
  138. begin
  139.   if not FindFieldInfo(Field, FieldID, AttrID) then
  140.     raise Exception.CreateResFmt(@SDSFieldNotInDict, [Field.FullName]);
  141. end;
  142.  
  143. function TBDEDesigner.FindFieldInfo(Field: TField; var FieldID: TFieldID;
  144.   var AttrID: TAttrID): Boolean;
  145. var
  146.   DatabaseName, TableName: string;
  147. begin
  148.   GetTableDesc(Databasename, TableName);
  149.   AttrID := NullAttrID;
  150.   FieldID := FindFieldID(FindTableID(FindDatabaseID(DatabaseName), TableName),
  151.     Field.FieldName);
  152.   if not IsNullID(FieldID) then
  153.     AttrID := GetAttrID(FieldID)
  154.   else if Field.AttributeSet <> '' then
  155.     AttrID := FindAttrID(Field.AttributeSet);
  156.   Result := not IsNullID(FieldID) or not IsNullID(AttrID);
  157. end;
  158.  
  159. function TBDEDesigner.RetrieveAttributes(Field: TField): Boolean;
  160. var
  161.   FieldID: TFieldID;
  162.   AttrID: TAttrID;
  163. begin
  164.   if FindFieldInfo(Field, FieldID, AttrID) then
  165.   begin
  166.     UpdateField(Field, FieldID, AttrID);
  167.     Field.AttributeSet := GetAttrName(AttrID);
  168.   end;
  169.   Result := True;
  170. end;
  171.  
  172. function TBDEDesigner.SaveAttributes(Field: TField): Boolean;
  173. var
  174.   FieldID: TFieldID;
  175.   AttrID: TAttrID;
  176. begin
  177.   Result := True;
  178.   GetFieldInfo(Field, FieldID, AttrID);
  179.   if not IsNullID(AttrID) then
  180.     UpdateAttr(Field, FieldID, AttrID)
  181.   else
  182.     Result := SaveAttributesAs(Field);
  183. end;
  184.  
  185. function TBDEDesigner.SaveAttributesAs(Field: TField): Boolean;
  186. var
  187.   DatabaseName, TableName, AttributeName: string;
  188.   FieldID: TFieldID;
  189.   AttrID: TAttrID;
  190. begin
  191.   GetTableDesc(DatabaseName, TableName);
  192.   GetFieldInfo(Field, FieldID, AttrID);
  193.   Result := SaveAttributesAsDlg(TableName, Field.FieldName, AttributeName, AttrID);
  194.   if Result then NewAttr(Field, FieldID, AttributeName, AttrID);
  195. end;
  196.  
  197. function TBDEDesigner.AssociateAttributes(Field: TField): Boolean;
  198. var
  199.   FieldID: TFieldID;
  200.   AttrID: TAttrID;
  201. begin
  202.   FindFieldInfo(Field, FieldID, AttrID);
  203.   if GetAssociateAttributes(AttrID, Result) then
  204.   begin
  205.     if not IsNullID(FieldID) then AssociateAttr(AttrID, FieldID);
  206.     UpdateField(Field, FieldID, AttrID);
  207.     Field.AttributeSet := GetAttrName(AttrID);
  208.   end;
  209. end;
  210.  
  211. function TBDEDesigner.UnassociateAttributes(Field: TField): Boolean;
  212. var
  213.   FieldID: TFieldID;
  214.   AttrID: TAttrID;
  215. begin
  216.   Field.AttributeSet := '';
  217.   FindFieldInfo(Field, FieldID, AttrID);
  218.   if not IsNullID(FieldID) then UnassociateAttr(FieldID);
  219.   Field.AttributeSet := '';
  220.   Result := True;
  221. end;
  222.  
  223. procedure TBDEDesigner.AttributeClick(Sender: TObject);
  224. var
  225.   MenuID: TMenuItemID;
  226.   Proc: TSelectionProc;
  227. begin
  228.   if Assigned(Sender) and (Sender is TComponent) then
  229.     MenuID := TMenuItemID(TComponent(Sender).Tag) else
  230.     MenuID := miSeparator;
  231.   try
  232.     case MenuID of
  233.       miRetrieve: Proc := RetrieveAttributes;
  234.       miSave: Proc := SaveAttributes;
  235.       miSaveAs: Proc := SaveAttributesAs;
  236.       miAssociate: Proc := AssociateAttributes;
  237.       miUnassociate: Proc := UnassociateAttributes;
  238.     else
  239.       Proc := nil;
  240.     end;
  241.     if Assigned(Proc) then
  242.       FieldsEditor.ForEachSelection(Proc);
  243.   finally
  244.     if MenuID in [miAssociate, miRetrieve] then
  245.       FieldsEditor.Designer.Modified;
  246.   end;
  247. end;
  248.  
  249. function TBDEDesigner.GetControlClass(Field: TField): string;
  250. var
  251.   FieldID: TFieldID;
  252.   AttrId: TAttrID;
  253. begin
  254.   if Assigned(Field) then
  255.   begin
  256.     FindFieldInfo(Field, FieldID, AttrID);
  257.     Result := DRIntf.GetControlClass(AttrID);
  258.   end else
  259.     Result := '';
  260.   if Result = '' then
  261.     Result := inherited GetControlClass(Field);
  262. end;
  263.  
  264. procedure TBDEDesigner.BeginCreateFields;
  265. var
  266.   DatabaseName, TableName: string;
  267. begin
  268.   if Dataset is TTable then
  269.   begin
  270.     GetTableDesc(DatabaseName, TableName);
  271.     FTableID := FindTableID(FindDatabaseID(DatabaseName), TableName);
  272.   end
  273.   else
  274.   if Dataset is TQuery then
  275.   begin
  276.     FQueryDescs := TQueryDescription.Create(nil);
  277.     try
  278.       FQueryDescs.Query := TQuery(Dataset);
  279.       FQueryDescs.Open;
  280.     except
  281.       FQueryDescs.Free;
  282.       FQueryDescs := nil;
  283.     end;
  284.   end;
  285.   inherited BeginCreateFields;
  286. end;
  287.  
  288. procedure TBDEDesigner.EndCreateFields;
  289. begin
  290.   FQueryDescs.Free;
  291.   FQueryDescs := nil;
  292.   FTableID := NullTableId;
  293.   inherited EndCreateFields;
  294. end;
  295.  
  296. function TBDEDesigner.DoCreateField(const FieldName: string; Origin: string): TField;
  297. var
  298.   FieldID: TFieldID;
  299.   AttrID: TAttrID;
  300.   DatabaseName: string;
  301.   TableName: string;
  302.   FldName: string;
  303.  
  304.   function NeedsBackslashing(const Name: string): Boolean;
  305.   var
  306.     N: PChar;
  307.   begin
  308.     Result := True;
  309.     N := PChar(Pointer(Name));
  310.     while N^ <> #0 do
  311.       if N^ in ['\','"'] then Exit
  312.       else if N^ in LeadBytes then Inc(N, 2)
  313.       else Inc(N);
  314.     Result := False;
  315.   end;
  316.  
  317.   function Backslash(const Name: string): string;
  318.   var
  319.     CName: array[0..1024] of Char;
  320.     N, C: PChar;
  321.   begin
  322.     N := PChar(Pointer(Name));
  323.     C := CName;
  324.     while N^ <> #0 do
  325.     begin
  326.       if N^ in ['\', '"'] then
  327.       begin
  328.         C^ := '\';
  329.         Inc(C);
  330.       end;
  331.       C^ := N^;
  332.       if N^ in LeadBytes then
  333.       begin
  334.         Inc(C);
  335.         Inc(N);
  336.         C^ := N^;
  337.       end;
  338.       Inc(C);
  339.       Inc(N);
  340.     end;
  341.     SetString(Result, CName, C - CName);
  342.   end;
  343.  
  344.   function Delimit(const Name: string): string;
  345.   begin
  346.     Result := Name;
  347.     if NeedsBackslashing(Result) then Result := Backslash(Result);
  348.     if Pos('.', Name) <> 0 then Result := '"' + Result + '"';
  349.   end;
  350.  
  351. begin
  352.   FieldID := NullFieldID;
  353.   AttrID := NullAttrID;
  354.   if Origin = '' then
  355.   begin
  356.     if DataSet is TTable then
  357.     begin
  358.       FieldID := FindFieldID(FTableID, FieldName);
  359.       AttrID := GetAttrID(FieldID);
  360.       Origin := '';
  361.     end else
  362.     if DataSet is TQuery then
  363.     try
  364.       FQueryDescs.RecNo := DataSet.FieldDefs.Find(FieldName).FieldNo;
  365.       DatabaseName := FQueryDescs['DATABASE']; { Do not localize }
  366.       TableName := FQueryDescs['TABLENAME']; { Do not localize }
  367.       FldName := FQueryDescs['FIELDNAME']; { Do not localize }
  368.       FieldID := FindFieldID(FindTableID(FindDatabaseID(DatabaseName),
  369.         QualifyTableName(DatabaseName, nil, FQueryDescs['TABLENAME'])), { Do not localize }
  370.         FQueryDescs['FIELDNAME']); { Do not localize }
  371.       AttrID := GetAttrID(FieldID);
  372.       Origin := Delimit(TableName) + '.' + Delimit(FldName);
  373.       if (TQuery(Dataset).Database = nil) or
  374.          AnsiSameText(TQuery(Dataset).DatabaseName, DatabaseName) then
  375.         Origin := Delimit(DatabaseName) + '.' + Origin;
  376.     except
  377.       FieldID := NullFieldID;
  378.       AttrID := NullAttrID;
  379.       Origin := '';
  380.     end;
  381.   end;
  382.   Result := inherited DoCreateField(FieldName, Origin);
  383.   try
  384.     if DictionaryActive then UpdateField(Result, FieldID, AttrID);
  385.   except
  386.     Result.Free;
  387.     raise;
  388.   end;
  389. end;
  390.  
  391. procedure TBDEDesigner.InitializeMenu(Menu: TPopupMenu);
  392. type
  393.   TMenuInfo = record
  394.     Name: string;
  395.     HelpContext: Integer;
  396.     Caption: string;
  397.     ShortCut: string;
  398.     Tag: TMenuItemID;
  399.   end;
  400. const
  401.   AttributeMenus: array[TMenuItemID] of TMenuInfo = (
  402.    (Name: 'N2'; HelpContext: 0; Caption: '-'; ShortCut: ''; Tag: miSeparator), { Do not localize }
  403.    (Name: 'RetrieveItem'; HelpContext: 30138; Caption: SRetrieveAttributes;{ Do not localize }
  404.     ShortCut: 'Ctrl+R'; Tag: miRetrieve),{ Do not localize }
  405.    (Name: 'UpdateItem'; HelpContext: 30139; Caption: SSaveAttributes;{ Do not localize }
  406.     ShortCut: 'Ctrl+S'; Tag: miSave),{ Do not localize }
  407.    (Name: 'SaveAttributesAsItem'; HelpContext: 30140; Caption: SSaveAttributesAs;{ Do not localize }
  408.     ShortCut: 'Ctrl+E'; Tag: miSaveAs),{ Do not localize }
  409.    (Name: 'AssociateItem'; HelpContext: 30141; Caption: SAssociateAttributes;{ Do not localize }
  410.     ShortCut: 'Ctrl+O'; Tag: miAssociate),{ Do not localize }
  411.    (Name: 'Unassociate'; HelpContext: 30142; Caption: SUnassociateAttributes;{ Do not localize }
  412.     ShortCut: 'Ctrl+U'; Tag: miUnassociate){ Do not localize }
  413.   );
  414. var
  415.   i: TMenuItemID;
  416. begin
  417.   FTableID := NullTableID;
  418.   FQueryDescs := nil;
  419.   inherited InitializeMenu(Menu);
  420.   for i := Low(AttributeMenus) to High(AttributeMenus) do
  421.   begin
  422.     FMenuArray[i] := TMenuItem.Create(nil);
  423.     FMenuArray[i].Name := AttributeMenus[i].Name;
  424.     FMenuArray[i].HelpContext := AttributeMenus[i].HelpContext;
  425.     FMenuArray[i].Caption := AttributeMenus[i].Caption;
  426.     if AttributeMenus[i].ShortCut <> '' then
  427.       FMenuArray[i].ShortCut := TextToShortCut(AttributeMenus[i].ShortCut);
  428.     FMenuArray[i].Tag := Integer(AttributeMenus[i].Tag);
  429.     FMenuArray[i].OnClick := AttributeClick;
  430.     Menu.Items.Add(FMenuArray[i]);
  431.   end;
  432. end;
  433.  
  434. procedure TBDEDesigner.UpdateMenus(Menu: TPopupMenu; EditState: TEditState);
  435. var
  436.   i: TMenuItemID;
  437.   Active: Boolean;
  438.   HasAttributes: Boolean;
  439.   Update: Boolean;
  440.   HasSelection: Boolean;
  441. begin
  442.   inherited UpdateMenus(Menu, EditState);
  443.   HasSelection := esCanCopy in EditState;
  444.   Active := DictionaryActive;
  445.   Update := HasSelection and Active;
  446.   HasAttributes := HasSelection and Update and not FieldsEditor.ForEachSelection(CheckAttribute);
  447.   for i := Low(FMenuArray) to High(FMenuArray) do
  448.     if Assigned(FMenuArray[i]) then
  449.       case i of
  450.         miRetrieve: FMenuArray[i].Enabled := HasSelection and Active;
  451.         miSave: FMenuArray[i].Enabled := HasAttributes;
  452.         miSaveAs: FMenuArray[i].Enabled := HasAttributes or (Update and (DataSet is TTable));
  453.         miAssociate: FMenuArray[i].Enabled := Update;
  454.         miUnassociate: FMenuArray[i].Enabled := HasAttributes;
  455.       end;
  456. end;
  457.  
  458. function TDBDataSetEditor.GetDSDesignerClass: TDSDesignerClass;
  459. begin
  460.   Result := TBDEDesigner;
  461. end;
  462.  
  463. procedure TDBDataSetEditor.ExecuteVerb(Index: Integer);
  464. begin
  465.   if Index <= inherited GetVerbCount - 1 then
  466.     inherited ExecuteVerb(Index) else
  467.   begin
  468.     Dec(Index, inherited GetVerbCount);
  469.     case Index of
  470.       0: ExploreDataset(TDBDataset(Component));
  471.     end;
  472.   end;
  473. end;
  474.  
  475. function TDBDataSetEditor.GetVerb(Index: Integer): string;
  476. begin
  477.   if Index <= inherited GetVerbCount - 1 then
  478.     Result := inherited GetVerb(Index) else
  479.   begin
  480.     Dec(Index, inherited GetVerbCount);
  481.     case Index of
  482.       0: Result := SExplore;
  483.     end;
  484.   end;
  485. end;
  486.  
  487. function TDBDataSetEditor.GetVerbCount: Integer;
  488. begin
  489.   Result := inherited GetVerbCount + 1;
  490. end;
  491.  
  492. procedure TQueryEditor.ExecuteVerb(Index: Integer);
  493. var
  494.   Database: TDatabase;
  495.   Query: TQuery;
  496. begin
  497.   if Index < inherited GetVerbCount then
  498.     inherited ExecuteVerb(Index) else
  499.   begin
  500.     Query := Component as TQuery;
  501.     Dec(Index, inherited GetVerbCount);
  502.     case Index of
  503.       0: Query.ExecSQL;
  504.       1:
  505.       if GQELoaded then
  506.       begin
  507.         Database := Query.OpenDatabase;
  508.         try
  509.           BuildQuery(Query);
  510.         finally
  511.           Query.CloseDatabase(Database);
  512.         end;
  513.         if Designer <> nil then Designer.Modified;
  514.       end;
  515.     end;
  516.   end;
  517. end;
  518.  
  519. function TQueryEditor.GetVerb(Index: Integer): string;
  520. begin
  521.   if Index < inherited GetVerbCount then
  522.     Result := inherited GetVerb(Index) else
  523.   begin
  524.     Dec(Index, inherited GetVerbCount);
  525.     case Index of
  526.       0: Result := SExecute;
  527.       1: if GQELoaded then Result := SGQEVerb;
  528.     end;
  529.   end;
  530. end;
  531.  
  532. function TQueryEditor.GetVerbCount: Integer;
  533. begin
  534.   Result := inherited GetVerbCount + 1 + Ord(LoadGQE);
  535. end;
  536.  
  537. procedure TStoredProcEditor.ExecuteVerb(Index: Integer);
  538. begin
  539.   if Index < inherited GetVerbCount then
  540.     inherited ExecuteVerb(Index) else
  541.   begin
  542.     Dec(Index, inherited GetVerbCount);
  543.     if Index = 0 then (Component as TStoredProc).ExecProc;
  544.   end;
  545. end;
  546.  
  547. function TStoredProcEditor.GetVerb(Index: Integer): string;
  548. begin
  549.   if Index < inherited GetVerbCount then
  550.     Result := inherited GetVerb(Index) else
  551.   begin
  552.     Dec(Index, inherited GetVerbCount);
  553.     if Index = 0 then Result := SExecute;
  554.   end;
  555. end;
  556.  
  557. function TStoredProcEditor.GetVerbCount: Integer;
  558. begin
  559.   Result := inherited GetVerbCount + 1;
  560. end;
  561.  
  562. function IsDatabaseOpen(DataSet: TDBDataSet): Boolean;
  563. var
  564.   Session: TSession;
  565.   DB: TDatabase;
  566. begin
  567.   Result := False;
  568.   with DataSet do
  569.   begin
  570.     Session := Sessions.FindSession(SessionName);
  571.     if Session <> nil then
  572.     begin
  573.       DB := Session.FindDatabase(DatabaseName);
  574.       Result := (DB <> nil) and DB.Connected;
  575.     end;
  576.   end;
  577. end;
  578.  
  579. procedure TTableEditor.UpdateActions;
  580. const
  581.   ExistsActions: array [Boolean] of TTableDesignActions =
  582.     ([tdCreate, tdUpdate], [tdDelete, tdUpdate, tdRename]);
  583. begin
  584.   FActions := [];
  585.   if IsDatabaseOpen(TTable(Component)) then
  586.   try
  587.     FActions := ExistsActions[TTable(Component).Exists];
  588.     if (tdCreate in FActions) and (TTable(Component).FieldDefs.Count = 0) then
  589.       Exclude(FActions, tdCreate);
  590.     if (tdUpdate in FActions) and (TTable(Component).TableName = '') then
  591.       Exclude(FActions, tdUpdate);
  592.   except
  593.   end;
  594. end;
  595.  
  596. function TTableEditor.IndexToAction(Index: Integer): TTableDesignAction;
  597. begin
  598.   for Result := Low(TTableDesignAction) to High(TTableDesignAction) do
  599.     if Result in FActions then if Index = 0 then Exit else Dec(Index);
  600.   Result := tdCreate; // Error
  601. end;
  602.  
  603. procedure TTableEditor.ExecuteVerb(Index: Integer);
  604. var
  605.   I: Integer;
  606. begin
  607.   I := inherited GetVerbCount;
  608.   if Index < I then inherited
  609.   else if TableDesigner(TTable(Component), IndexToAction(Index - I)) then
  610.     Designer.Modified;
  611. end;
  612.  
  613. function TTableEditor.GetVerb(Index: Integer): string;
  614. var
  615.   I: Integer;
  616. begin
  617.   I := inherited GetVerbCount;
  618.   if Index < I then
  619.     Result := inherited GetVerb(Index) else
  620.     Result := TableDesignMenu[IndexToAction(Index - I)];
  621. end;
  622.  
  623. function TTableEditor.GetVerbCount: Integer;
  624. var
  625.   T: TTableDesignAction;
  626. begin
  627.   Result := inherited GetVerbCount;
  628.   UpdateActions;
  629.   for T := Low(TableDesignMenu) to High(TableDesignMenu) do
  630.     if T in FActions then Inc(Result);
  631. end;
  632.  
  633. end.
  634.